//
// Created by Lai on 2020/12/3.
//

#ifndef OPENGLDEMO_COMMGL_HPP
#define OPENGLDEMO_COMMGL_HPP

#include <GLES3/gl3.h>
#include <map>
#include <vector>

enum GLShaderType {
    SHADER_VERTEX = 1,
    SHADER_FRAGMENT = 2
};


class GLShader {
public:
    GLShader(char *shaderStr, GLShaderType type);

    ~GLShader();

    GLuint shader = 0;
};


class GLProgram {
public:
    GLProgram(char *vertexShaderStr, char *fragmentShaderSrc);

    ~GLProgram();

    int useProgram();

    void OnSurfaceChanged(int x, int y, int width, int height) {
        glViewport(x, y, width, height);
    }

public:
    GLuint program = 0;
};


class TextVertex {
public:
    TextVertex();

    ~TextVertex();

    void UpdateVertexVbo2D(float *data, int vertexCount);

    void UpdateUvVbo2D(float *data, int vertexCount);

    void updateIndex(unsigned int *indexData, int indexCount);


    int InitEbo(unsigned int *indexData, int indexCount);
    int InitUvVbo2D(float *data, int vertexCount, GLuint layout);
    int InitVertexVbo2D(float *data, int vertexCount, GLuint layout);

    void BindVAO() const;

    void UnBindVAO();

    int childId;
    GLuint vao;
    GLuint vertexVbo;
    GLuint uvVbo;
    GLuint ebo;

    void BindVertex(GLuint vertexLayout, GLuint uvLayout);
};

class TextGroup {
public:
    TextGroup();

    ~TextGroup();

    int FindTextVertex(int childId, TextVertex *&pVao);

    int BindVertex(int childId, GLuint vertexLayout, GLuint uvLayout);

    void UpdateVertexVbo2D(int childId, float *data, int vertexCount);

    void UpdateUvVbo2D(int childId, float *data, int vertexCount);

    int updateIndex(int childId, unsigned int *indexData, int indexCount);

    void ClearVbo(int childId);

    std::vector<TextVertex *> allTextVertex;

    void BindVao(int childId);

    void UnBindVao(int childId);

    void CreateVertex(int childId);
};

class VaoGroupManager {
    std::map<int, TextGroup *> vaoGroupMap;

public:
    VaoGroupManager();

    ~VaoGroupManager();

    int CreateTextGroup(int id, TextGroup **vaoGroup);

    int RemoveId(int id);

    int FindGroup(int id, TextGroup *&pVaoGroup);

    void PrintAll();
};


class GLVAO {
public:
    GLVAO();

    ~GLVAO();

    GLuint AddVertex3D(float *data, int vertexCount, GLuint layout);

    GLuint AddVertex2D(float *data, int vertexCount, GLuint layout);

    GLuint setIndex(unsigned int *indexData, int indexCount);

    GLuint updateIndex(unsigned int *indexData, int indexCount) const;

    int BindVAO() const;

    void updateVertex2D(GLuint updateFbo, float *data, int vertexCount, GLuint layout);

    void subDataVertex2D(GLuint updateFbo, float *data, int vertexCount);

    void subDataIndex2D(unsigned int *indexData, int indexCount);

    GLuint setVertex2D(GLuint &fbo, float *data, int vertexCount, GLuint layout);

private:
    GLuint vao = 0;
    GLuint ebo = 0;
    std::vector<GLuint> vboList;
};

#endif //OPENGLDEMO_COMMGL_HPP
